package com.rtsapp.server.network.protocol.rpc.client.impl;

import com.rtsapp.server.bytecode.ClassGenerator;
import com.rtsapp.server.utils.ReflectionUtils;
import com.rtsapp.server.logger.Logger;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Created by admin on 15-10-17.
 */
public class SyncRPCClient extends RPCClientImpl {

    private static final Logger LOGGER =com.rtsapp.server.logger.LoggerFactory.getLogger(SyncRPCClient.class);

    private static final ConcurrentMap<Class, Class> serviceClasses = new ConcurrentHashMap<>();
    private static final ConcurrentMap<Class, String> serviceNames = new ConcurrentHashMap<>();

    /**
     * 注册Class, 生成RPC代理的Class
     * 该方法不是线程安全的, 一般再服务器启动时调用
     *
     * @param clazz
     */
//    public static void registerProxyClass(Class<?> clazz, String serviceName) {
//        Class proxyClass = serviceClasses.get(clazz);
//        if (proxyClass == null) {
//            LOGGER.info("create proxy class for " + clazz.getName());
//            proxyClass = createProxyClass(clazz, serviceName);
//            if (proxyClass != null) {
//                serviceClasses.put(clazz, proxyClass);
//            } else {
//                LOGGER.error("error in create proxy class for " + clazz.getName());
//                throw new RuntimeException("error in create proxy class for " + clazz.getName());
//            }
//
//        } else {
//            LOGGER.info("proxy class for " + clazz.getName() + " is allready exist");
//        }
//    }


    public static void registerProxyClass(Class<?> clazz, Class<?> proxyClazz , String serviceName ) {
        Class proxyClass = serviceClasses.get(clazz);
        if (proxyClass == null) {
            serviceClasses.put( clazz, proxyClazz);
            serviceNames.put(clazz, serviceName);
        } else {
            LOGGER.info("proxy class for " + clazz.getName() + " is allready exist");
        }
    }

    public <T> T getProxy(Class<?> clazz, String ip, int port) throws IllegalAccessException, InstantiationException, RuntimeException {
        return this.getProxy(clazz,ip,port,20480);
    }

    /**
     * 获取一个代理, 如果对象池中有对象，返回对象池中的对象
     *
     * @param clazz
     * @param ip
     * @param port
     * @param <T>
     * @return
     */
    public <T> T getProxy(Class<?> clazz, String ip, int port,int maxFrameLength) throws IllegalAccessException, InstantiationException, RuntimeException {

        Class proxyClass = serviceClasses.get( clazz );
        String serviceName = serviceNames.get(clazz);

        if (proxyClass == null) {
            throw new RuntimeException("proxy class is not exist, please call registerProxyClass() first");
        }

        Object obj = proxyClass.newInstance();

        SyncProxyInterface proxyService = (SyncProxyInterface) obj;
        RPCClientProxy rpcProxy = createSyncRPCProxy(ip, port, maxFrameLength);
        if (rpcProxy == null) {
            throw new RuntimeException("cannot create proxy ");
        }
        proxyService.setSyncRPCProxy( rpcProxy);
        proxyService.setServiceName( serviceName );

        return (T) obj;
    }


    /**
     * 释放代理, 代理被放入到对象池中
     * @param proxy
     */
//    public void releaseProxy( Object proxy ){
//        throw new java.lang.RuntimeException( "该方法还没实现, 先调用closeProxy吧" );
//    }

    /**
     * 关闭代理, 代理被删除
     *
     * @param proxy
     */
//    public void closeProxy(Object proxy) {
//
//
//
//        if (proxy == null) {
//            return;
//        }
//
//        if (proxy instanceof SyncProxyInterface ) {
//            SyncProxyInterface proxyService = (SyncProxyInterface) proxy;
//            RPCClientProxy rpcProxy = proxyService.getSyncRPCProxy();
//        }
//
//
//    }


    private RPCClientProxy createSyncRPCProxy(String ip, int port,int maxFrameLength) {

        ClientCfg cfg = new ClientCfg();
        cfg.setIp(ip);
        cfg.setPort(port);
        cfg.setNum(1);
        cfg.setServerName(ip + ":" + port);
        cfg.setMaxFrameLength(maxFrameLength);

        RPCClientProxy proxy = this.getRPCClientProxy( cfg.getServerName() ) ;
        if( proxy == null ){
            this.addClientProxyAfterStart(  cfg );
            proxy = this.getRPCClientProxy( cfg.getServerName( ) );
        }

        return proxy;

    }


    private static Class createProxyClass(Class<?> clazz, String serviceName) {

        ClassGenerator cg = ClassGenerator.newInstance();

        //导入包
        cg.importPackage("com.rtsapp.server.network.protocol.rpc.client.impl");
        cg.importPackage(clazz.getPackage().getName());

        // 类名，接口
        cg.setClassName(clazz.getName() + "_RPCProxy");
        cg.addInterface(clazz);
        cg.addInterface(SyncProxyInterface.class);


        //SyncRPCProxy属性,set,get方法
        cg.addField("rpcProxy", Modifier.PRIVATE, RPCClientProxy.class);
        cg.addMethod("public void setSyncRPCProxy( com.rtsapp.server.network.protocol.rpc.client.impl.SyncRPCProxy proxy ){ this.rpcProxy = proxy; }");
        cg.addMethod("public com.rtsapp.server.network.protocol.rpc.client.impl.SyncRPCProxy getSyncRPCProxy( ){ return this.rpcProxy; }");

        cg.addField("serviceName", Modifier.PRIVATE, String.class);
        cg.addMethod("public void setServiceName( java.lang.String serviceName ){ this.serviceName = serviceName; }");
        cg.addMethod("public java.lang.String getServiceName( ){ return this.serviceName; }");


        //重写所有的方法
        Method[] methods = clazz.getMethods();
        if (methods != null) {
            for (Method m : methods) {

                String methodName = m.getName();
                String returnType = m.getReturnType().getName();

                StringBuilder sb = new StringBuilder();
                sb.append("public " + returnType + " " + methodName + "(");

                Class[] parameters = m.getParameterTypes();
                for (int i = 0; i < parameters.length; i++) {
                    if (i > 0) {
                        sb.append(",");
                    }
                    sb.append(ReflectionUtils.getTypeName(m.getParameterTypes()[i]) + " p" + i);
                }
                sb.append("){");

                sb.append( "Object[] params = new Object[" + parameters.length+" ];" );
                for( int i = 0; i < parameters.length; i++ ){
                    sb.append( "params["+i+"]=p"+i + ";"  );
                }

                sb.append(" Object result =  rpcProxy.call(  \"" + serviceName + "\",\"" + methodName + "\", params );\r\n");

                if( !"void".equalsIgnoreCase( returnType ) ){
                    sb.append( "return (" + returnType + ")result;" );
                }
                sb.append("}");

                cg.addMethod(sb.toString());
            }
        }


        //加入构造函数
        cg.addDefaultConstructor();

        //生成class
        return cg.toClass();
    }




}
